package com.lyz.remote.impl;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.zip.GZIPOutputStream;

import org.apache.log4j.Logger;

import com.lyz.config.ConfigFactory;
import com.lyz.config.IConfig;
import com.lyz.core.impl.Context;
import com.lyz.log.filter.IFilter;
import com.lyz.remote.IMsgHandler;
import com.lyz.util.ClassUtil;
import com.lyz.util.PropertiesUtil;
import com.lyz.util.SleepUtil;
/**
 * 连接建立之后，客户端需要将tag发送给服务器端，以告知该连接传输的是什么日志。
 * 服务器会返回相同的tag表明接受连接
 * 服务器端会根据配置考虑是按照服务器分开存储，还是统一存储。
 * @author luyongzhao
 *
 */
public class SocketMsgHandler implements IMsgHandler {
	
	private static final Logger logger = Logger.getLogger(SocketMsgHandler.class);
	
//	private static final String RESP_SUCCESS = "200";
	
	/*一个文件传输只需要一个socket*/
	private Socket socket;
	/*标签，以辨别该socket传输的是哪种日志文件*/
	private String tag;
	
	private IFilter filter = null;
	
	private IConfig config = null;
	
	private BufferedOutputStream bos = null;
	
	private boolean needFlush = false;
	

	public IMsgHandler initHandler(String tag, Context context) {
		this.tag = tag;
		config = ConfigFactory.getConfig();
		needFlush = config.getNeedFlush(tag);
		filter = (IFilter)ClassUtil.newInstance(config.getFilter(tag));
		return this;
	}
	
	private String createTag(String tag){
		if(tag==null || "".equals(tag.trim())){
			return null;
		}
		/*服务器端采用mina，文本过滤器，必须有换行符，否则服务器端会等待*/
		return "logsyncer:"+tag+"\n";
//		return "logsyncer:"+tag;
	}
	
	/**
	 * 获取一个已连接的socket
	 * @return
	 */
	private Socket getSocket(){
		/*首次连接，进行协议交互*/
		try {
			if(socket==null || socket.isOutputShutdown() || socket.isClosed()){
				this.closeSocket();
				socket = new Socket(config.getServerIp(tag), config.getServerPort(tag));
				bos = new BufferedOutputStream(socket.getOutputStream(),config.getBytesBufferSize());
				bos.write(createTag(tag).getBytes());
				bos.flush();
				logger.info("write tag:"+tag);
				/*等待服务器返回接收信息*/
				BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				String resp = reader.readLine();
				if(resp!=null && tag.equals(resp.trim())){
					logger.info("receive response tag:"+tag);
					return socket;
				}else{
					logger.warn("error response from server:"+resp);
					closeSocket();
					return null;
				}
			}
			return socket;
		} catch (UnknownHostException e) {
			logger.error("ip is wrong",e);
			closeSocket();
			return null;
		} catch (Exception e) {
			logger.warn("exception when connect to server",e);
			closeSocket();
			return null;
		}		
	}
	
	
	
	public void closeSocket(){
		try {
			if(socket != null){
				socket.close();
				socket = null;
//				writer = null;
			}
			if(bos != null){
				bos.close();
				bos = null;
			}
		} catch (IOException e) {
			logger.warn("fail to close socket",e);
		}
	}

	public boolean sendMsg(String msg) {
		
		if(msg == null || "".equals(msg.trim())){
			logger.debug("msg is empty...");
			return true;
		}
		/*过滤数据*/
		msg = filter.filter(msg);
		if(msg == null){
			return true;
		}
		boolean flag = false;
		
		/*保证消息不被丢弃*/
		do{
			/*按行读取时，会去除回车，此处补充上*/
			flag = doSendMsg(msg+"\n");
			
		}while(!flag);
		
		return true;
		
	}
	/**
	 * 实际的发送操作
	 * @param msg
	 * @return
	 */
	private boolean doSendMsg(String msg){
		
		try {
			/*获取连接socket*/
			do{
				socket = getSocket();
				if(socket == null){
					logger.info("fail to connect to log server...");
					SleepUtil.sleep(5000);
				}
			}while(socket == null);
			
			return writeMsg(msg);
		} catch (Exception e) {
			logger.error("fail to send message!",e);
			return false;
		}
	}
	
	private boolean writeMsg(String msg){
		try {
			/*必须得有换行符*/
//			socket.getOutputStream().write((msg+"\n").getBytes("UTF-8"));
//			socket.getOutputStream().write((msg).getBytes("UTF-8"));
//			socket.getOutputStream().flush();
			bos.write((msg).getBytes("UTF-8"));
			if(needFlush){
				bos.flush();
				logger.info("flush...");
			}
		} catch (Exception e) {
			logger.error("writer is null!",e);
			closeSocket();
			return false;
		}
		return true;
	}

	public boolean sendMsg(byte[] msg) {
		if(msg == null || msg.length==0){
			logger.debug("msg is empty...");
			return true;
		}
		boolean flag = false;
		/*保证消息不被丢弃*/
		do{
			flag = doSendMsg(msg);
			
		}while(!flag);
		
		return true;
	}
	
	private boolean doSendMsg(byte[] msg){
		
		try {
			/*获取连接socket*/
			do{
				socket = getSocket();
				if(socket == null){
					logger.info("fail to connect to log server...");
					SleepUtil.sleep(5000);
				}
			}while(socket == null);
			
			return writeMsg(msg);
		} catch (Exception e) {
			logger.error("fail to send message!",e);
			return false;
		}
	}
	
	private boolean writeMsg(byte[] msg){
		try {
			bos.write(msg);
			if(needFlush){
				bos.flush();
				logger.info("flush...");
			}
		} catch (Exception e) {
			logger.error("writer is null!",e);
			closeSocket();
			return false;
		}
		return true;
	}

	
	
	

}
